package com.stylefeng.guns.modular.qinhe.controller;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.stylefeng.guns.GunsApplication;
import com.stylefeng.guns.core.Download3DWarehouseTask;
import com.stylefeng.guns.core.DownloadZMTask;
import com.stylefeng.guns.core.base.controller.BaseController;
import com.stylefeng.guns.core.util.Hash;
import com.stylefeng.guns.modular.qinhe.service.ISuCategoryService;
import com.stylefeng.guns.modular.qinhe.service.ISuModelService;
import com.stylefeng.guns.modular.system.model.SuCategory;
import com.stylefeng.guns.modular.system.model.SuModel;
import com.stylefeng.guns.modular.system.service.IDictService;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author shmiluyu
 */
@Controller
@RequestMapping("/sumodel")
public class SuModelController extends BaseController {

  public static final String PREFIX = "/qinhe/";
  @Autowired
  private ISuCategoryService suCategoryService;
  @Autowired
  private IDictService dictService;
  @Autowired
  private ISuModelService suModelService;
  @Autowired
  private Download3DWarehouseTask download3DWarehouseTask;
  @Autowired
  private DownloadZMTask downloadZMTask;
  private static final SuCategory lastCat = new SuCategory();

  /**
   * 显示上传页面
   */
  @RequestMapping(value = "/display_upload", method = RequestMethod.GET)
  public String displayUpload(Model model) {
    model.addAttribute("parentCat",
        suCategoryService.selectList(new EntityWrapper<SuCategory>().eq("pid", 0)));
    model.addAttribute("childCat",
        suCategoryService.selectList(new EntityWrapper<SuCategory>().gt("pid", 0)));
    model.addAttribute("styles", dictService.selectByParentCode("su_styles"));
    return PREFIX + "display_upload.html";
  }
  //handle upload

  @PostMapping("/upload")
  @ResponseBody
  public Object upload(@RequestPart("file") MultipartFile zipFile,
      @RequestParam(defaultValue = "0") Integer vray,
      @RequestParam(defaultValue = "0") Integer enscape,
      @RequestParam(defaultValue = "0") Integer thea,
      @RequestParam(defaultValue = "0") Long oldid) throws IOException {
    //保存到数据库
    SuModel suModel;
    long filename;
    if (oldid > 0) {
      suModel = suModelService.selectById(oldid);
      filename = Long.parseLong(suModel.getFilename());
    } else {
      suModel = new SuModel();
      filename = System.currentTimeMillis();
    }
    File jarFolder = new ApplicationHome(GunsApplication.class).getDir();
    //jarFolder+"/models"+ "filename"
    String fileZip = "compressed.zip";
    byte[] buffer = new byte[1024];
    ZipInputStream zis = new ZipInputStream(zipFile.getInputStream());
    ZipEntry zipEntry = zis.getNextEntry();
    File newFileFolder = new File(
        jarFolder + "/models/");
    newFileFolder.mkdirs();
    String checksum = "";
    while (zipEntry != null) {
      File dest = new File(newFileFolder, +filename + "." + zipEntry.getName().split("\\.")[1]);
      FileOutputStream fos = new FileOutputStream(
          dest);
      int len;
      while ((len = zis.read(buffer)) > 0) {
        fos.write(buffer, 0, len);
      }
      fos.close();
      checksum = DatatypeConverter.printHexBinary(Hash.SHA256.checksum(dest)).toLowerCase();

      zipEntry = zis.getNextEntry();
    }
    zis.closeEntry();
    zis.close();

    suModel.setCategory(Long.parseLong(getPara("category")));
    suModel.setModelname(getPara("modelname"));
    suModel.setFilename(filename + "");
    suModel.setStyle(Long.parseLong(getPara("style")));
    suModel.setCreatetime(new Date());
    suModel.setUploader("test");
    suModel.setFilesize(new File(newFileFolder, +filename + ".skp").length());
    suModel.setVray(vray);
    suModel.setEnscape(enscape);
    suModel.setThea(thea);
    suModel.setChecksum(checksum);
    if (oldid > 0) {
      suModelService.updateById(suModel);
    } else {
      suModelService.insert(suModel);
    }
    return "success";
  }
  //

  @GetMapping({"/list/{categoryId}", "/list"})
  public String listModels(@PathVariable(value = "categoryId", required = false) Long cid,
      Model model, @RequestParam(defaultValue = "nothing") String mats,
      @RequestParam(defaultValue = "0") Integer root) {
    model.addAttribute("parentCat",
        suCategoryService.selectList(new EntityWrapper<SuCategory>().eq("pid", 0)));
    model.addAttribute("childCat",
        suCategoryService.selectList(new EntityWrapper<SuCategory>().gt("pid", 0)));
    model.addAttribute("styles", dictService.selectByParentCode("su_styles"));

    EntityWrapper<SuModel> wrapper = new EntityWrapper<>();
    if (cid != null) {
      setAttr("root", root);
      if (root == 1) {
        List<SuCategory> subCategories = suCategoryService
            .selectList(new EntityWrapper<SuCategory>().eq("pid", cid));
        Integer[] cids = new Integer[subCategories.size()];
        for (int i = 0; i < subCategories.size(); i++) {
          cids[i] = subCategories.get(i).getId().intValue();
        }
        wrapper.in("category", StringUtils.join(cids, ","));
      } else {
        SuCategory suCategory = suCategoryService.selectById(cid);
        model.addAttribute("suCategory", suCategory);
        wrapper.eq("category", cid);
      }
    }
    String style = getPara("styles");
    model.addAttribute("styles", dictService.selectByParentCode("su_styles"));
    if (StringUtils.isNotBlank(style)) {
      wrapper.in("style", style);
      String[] split = style.split(",");
      for (int i = 0; i < split.length; i++) {
        split[i] = StringUtils.wrap(split[i], "'");
      }
      model.addAttribute("filter_styles", StringUtils.join(split, ","));
    }
    if (StringUtils.contains(mats, "vray")) {
      wrapper.eq("vray", 1);
    }
    if (StringUtils.contains(mats, "enscape")) {
      wrapper.eq("enscape", 1);
    }
    if (StringUtils.contains(mats, "thea")) {
      wrapper.eq("thea", 1);
    }
    String[] split = mats.split(",");
    for (int i = 0; i < split.length; i++) {
      split[i] = StringUtils.wrap(split[i], "'");
    }
    model.addAttribute("mats", StringUtils.join(split, ","));
    String page = getPara("page");
    if (StringUtils.isBlank(page)) {
      page = "1";
    }
    wrapper.eq("deleted", 0);
    wrapper.eq("type", 1);
    wrapper.orderBy("downloads", false);
    wrapper.orderBy("createtime",false);
    Page<SuModel> suModelPage = suModelService
        .selectPage(new Page<>(Integer.parseInt(page), 60), wrapper);

    model.addAttribute("models", suModelPage);
    return PREFIX + "all.html";
  }

  @RequestMapping(value = "/push", method = RequestMethod.GET)
  public String push(String id, String thumb, String title, Model model) {
    model.addAttribute("parentCat",
        suCategoryService.selectList(new EntityWrapper<SuCategory>().eq("pid", 0)));
    model.addAttribute("childCat",
        suCategoryService.selectList(new EntityWrapper<SuCategory>().gt("pid", 0)));
    model.addAttribute("styles", dictService.selectByParentCode("su_styles"));
    model.addAttribute("id", id);
    model.addAttribute("thumb", thumb);
    model.addAttribute("title", StringEscapeUtils.escapeJava(title));
    model.addAttribute("lastCat",lastCat);
    return PREFIX + "display_push.html";
  }

  @PostMapping("/push")
  @ResponseBody
  public Object upload(String modelid, String thumbpath,
      String modelname, Long category, Long style,
      @RequestParam(defaultValue = "0") Integer vray,
      @RequestParam(defaultValue = "0") Integer enscape,
      @RequestParam(defaultValue = "0") Integer thea) throws IOException {
    SuModel suModel = new SuModel();
    suModel.setThea(thea);
    suModel.setVray(vray);
    suModel.setEnscape(enscape);
    suModel.setUploader("3DWarehouse");
    suModel.setCreatetime(new Date());
    suModel.setStyle(style);
    suModel.setModelname(modelname);
    suModel.setStyle(style);
    suModel.setCategory(category);
    lastCat.setId(category);
    download3DWarehouseTask.download(suModel, modelid, thumbpath);
    return SUCCESS_TIP;
  }

  @GetMapping("/config")
  public String showConfig() {
    return PREFIX + "cache_config.html";
  }

  @GetMapping("/update/checksum")
  @ResponseBody
  public Object updateChecksum() {
    List<SuModel> models = suModelService
        .selectList(new EntityWrapper<SuModel>().isNull("checksum"));
    File jarFolder = new ApplicationHome(GunsApplication.class).getDir();
    File newFileFolder = new File(
        jarFolder + "/models/");
    models.forEach(m -> {
      m.setChecksum(DatatypeConverter
          .printHexBinary(
              Hash.SHA256.checksum(new File(newFileFolder, m.getFilename() + ".skp")))
          .toLowerCase());
      suModelService.updateById(m);
    });
    return "success";
  }

  @GetMapping("/skm")
  public String listSkmPage(@RequestParam(defaultValue = "") String path) {
    return "";
  }

  @PostMapping("/delete/{id}")
  @ResponseBody
  public Object deleteModel(@PathVariable Long id) {
    SuModel suModel = suModelService.selectById(id);
    suModel.setDeleted(1);
    suModelService.updateById(suModel);
    return SUCCESS_TIP;
  }

  @PostMapping("/download/count/{id}")
  @ResponseBody
  public Object downloadCount(@PathVariable Long id) {
    suModelService.downloadCount(id);
    return SUCCESS_TIP;
  }

  @RequestMapping(value = "/push/zm/{mid}", method = RequestMethod.GET)
  public String pushZM(@PathVariable String mid,
      @RequestParam String sid,
      String thumb,
      String title,
      Model model) {
    model.addAttribute("sid", sid);
    model.addAttribute("parentCat",
        suCategoryService.selectList(new EntityWrapper<SuCategory>().eq("pid", 0)));
    model.addAttribute("childCat",
        suCategoryService.selectList(new EntityWrapper<SuCategory>().gt("pid", 0)));
    model.addAttribute("styles", dictService.selectByParentCode("su_styles"));
    model.addAttribute("id", mid);
    model.addAttribute("thumb", thumb);
    model.addAttribute("title", StringEscapeUtils.escapeJava(title));
    return PREFIX + "display_push_zm.html";
  }


  @PostMapping("/download_zm")
  @ResponseBody
  public Object downloadZM(String modelid, String thumbpath,
      String modelname, Long category, Long style, String session,
      @RequestParam(defaultValue = "0") Integer vray,
      @RequestParam(defaultValue = "0") Integer enscape,
      @RequestParam(defaultValue = "0") Integer thea) throws IOException {
    SuModel suModel = new SuModel();
    suModel.setThea(thea);
    suModel.setVray(vray);
    suModel.setEnscape(enscape);
    suModel.setUploader("ZhiMo");
    suModel.setCreatetime(new Date());
    suModel.setStyle(style);
    suModel.setModelname(modelname);
    suModel.setStyle(style);
    suModel.setCategory(category);
    downloadZMTask.download(suModel, session, modelid, thumbpath);
    return SUCCESS_TIP;
  }

  @GetMapping("/download/model/{filename}")
  public ResponseEntity<Resource> downloadModel(@PathVariable("filename") String filename)
      throws IOException {
    File home = new ApplicationHome(GunsApplication.class).getDir();

    File skpFile = new File(home + "/models/" + filename + ".skp");
    Path path = Paths.get(skpFile.getAbsolutePath());
    ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(path));

    return ResponseEntity.ok()
        .contentLength(skpFile.length())

        .contentType(MediaType.parseMediaType("application/octet-stream; charset=UTF-16LE"))
        .body(resource);
  }
}
